//
//  PurchaseManager.swift
//  ContactPoster
//
//  Created by TSYH on 2024/1/10.
//

import Foundation
import StoreKit
import Alamofire

public protocol PurchaseManagerDelegate: NSObjectProtocol {
    func purchase(_ manager: PurchaseManager, didChaged state: PremiumRequestState, object: Any?)
}

public class PurchaseManager: NSObject {
   @objc public static let `default` = PurchaseManager()
    
    // 请求商品数据，由外部配置
    public lazy var purchaseProducts = [PurchaseProduct]()
    
    struct Config {
        static let verifyUrl        = "https://buy.itunes.apple.com/verifyReceipt"
        static let sandBoxUrl       = "https://sandbox.itunes.apple.com/verifyReceipt"
    }
    
    lazy var products: [SKProduct] = []
    
    public weak var delegate: PurchaseManagerDelegate?
    
    // 会员信息
    var vipInformation: [String: Any] = [:]
    
    override init() {
        super.init()
        
        SKPaymentQueue.default().add(self)
        
        if let info = UserDefaults.standard.object(forKey: String.premiumExpiredInfo) as? [String: Any] {
            vipInformation = info
        }
    }
    
    public var expiredDate: Date? {
        guard let time = vipInformation["expireTime"] as? String else {
            return nil
        }
        return convertExpireDate(from: time)
    }
    private func convertExpireDate(from string: String) -> Date? {
        if let ts = TimeInterval(string) {
            let date = Date(timeIntervalSince1970: ts / 1000)
            return date
        }
        return nil
    }
    
    @objc public var isVip: Bool {
        #if DEBUG
        return false
        #endif
        guard let expiresDate = expiredDate else {
            return false
        }
        let todayStart = Calendar.current.startOfDay(for: Date())
        let todayStartTs = todayStart.timeIntervalSince1970
        let expiresTs = expiresDate.timeIntervalSince1970
        
        return expiresTs > todayStartTs
    }
    
    public var vipType: PremiumPeriod {
        guard isVip, let type = vipInformation["type"] as? String else {
            return .none
        }
        return PremiumPeriod(rawValue: type) ?? .none
    }
    
    /// 过期时间: 1683277585000 毫秒
    func updateExpireTime(_ timeInterval: String, 
                          for productId: String) {
        
        vipInformation.removeAll()
        vipInformation["expireTime"] = timeInterval
        vipInformation["productId"] = productId
        vipInformation["type"] = period(for: productId).rawValue
        
        UserDefaults.standard.set(vipInformation, forKey: String.premiumExpiredInfo)
        UserDefaults.standard.synchronize()
        
        NotificationCenter.default.post(name: .premiumStateDidChanged, object: nil)
    }
    
    // 商品id对应的时间周期
    func period(for productId: String) -> PremiumPeriod {
        return purchaseProducts.first(where: { $0.productId == productId })?.period ?? .none
    }
    
    // 时间周期对应的商品id
    func productId(for period: PremiumPeriod) -> String? {
        return purchaseProducts.first(where: { $0.period == period })?.productId
    }
}

// MARK: 商品信息
extension PurchaseManager {
    
    public func product(for period: PremiumPeriod) -> SKProduct? {
        return products.first(where: { $0.productIdentifier == productId(for: period) })
    }
    
    // 商品价格
    public func price(for period: PremiumPeriod) -> String? {
        guard let product = product(for: period) else {
            return nil
        }
        let formatter = NumberFormatter()
        formatter.formatterBehavior = NumberFormatter.Behavior.behavior10_4
        formatter.numberStyle = .currency
        formatter.locale = product.priceLocale
        return formatter.string(from: product.price)
    }
    
    public func originalPrice(for period: PremiumPeriod) -> String? {
        guard let product = product(for: period) else {
            return nil
        }
        switch period {
        case .year, .lifetime:
            // 5折
            let price = product.price.doubleValue
            let calculatePrice = price * 2
            let originStr = String(format: "%.2f", calculatePrice)
            let originPrice = NSDecimalNumber(string: originStr, locale: product.priceLocale)
            
            let formatter = NumberFormatter()
            formatter.formatterBehavior = NumberFormatter.Behavior.behavior10_4
            formatter.numberStyle = .currency
            formatter.locale = product.priceLocale
            return formatter.string(from: originPrice)
        default:
            return nil
        }
    }
}

// MARK: 商品 & 订阅请求
extension PurchaseManager {
    public func requestProducts() {
        if !products.isEmpty {
            delegate?.purchase(self, didChaged: .loadSuccess, object: nil)
        }
        
        delegate?.purchase(self, didChaged: .loading, object: nil)
        
        let request = SKProductsRequest(productIdentifiers: Set(purchaseProducts.map({ $0.productId })))
        request.delegate = self
        request.start()
    }
    
    public func restorePremium() {
        delegate?.purchase(self, didChaged: .restoreing, object: nil)
        SKPaymentQueue.default().restoreCompletedTransactions()
    }
    
    /// 支付
    public func pay(for period: PremiumPeriod) {
        guard SKPaymentQueue.canMakePayments() else {
            delegate?.purchase(self, didChaged: .payFail, object: "Payment failed, please check your payment account")
            return
        }
        
        guard SKPaymentQueue.default().transactions.count <= 0 else {
            delegate?.purchase(self, didChaged: .payFail, object: "You have outstanding orders that must be paid for before a new subscription can be placed.")
            restorePremium()
            return
        }
        if let product = product(for: period) {
            delegate?.purchase(self, didChaged: .paying, object: nil)
            let payment = SKPayment(product: product)
            SKPaymentQueue.default().add(payment)
        }
    }
}

// MARK: 商品回调
extension PurchaseManager: SKProductsRequestDelegate {
    public func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
        let products = response.products
        self.products = products
        delegate?.purchase(self, didChaged: .loadSuccess, object: nil)
        NotificationCenter.default.post(name: .premiumProductDataPrepared, object: nil)
    }
    
    public func request(_ request: SKRequest, didFailWithError error: Error) {
        delegate?.purchase(self, didChaged: .loadFail, object: error.localizedDescription)
    }
}

extension PurchaseManager {
    func filterTransactions(transactions:[SKPaymentTransaction]) -> [SKPaymentTransaction]{
        
        //1.按时间排序
        let sortedTransactions = transactions.sorted { transaction1, transaction2 in
            if let date1 = transaction1.transactionDate,let date2 = transaction2.transactionDate{
                return date1 > date2
            }
            return true
        }
         
        //2.进行分类
        var purchasingArray = [SKPaymentTransaction]()//购买中
        var purchasedArray = [SKPaymentTransaction]()//已购买
        var failedArray = [SKPaymentTransaction]()//购买失败
        var restoredArray = [SKPaymentTransaction]()//恢复购买
        var deferredArray = [SKPaymentTransaction]()//延期付款
        
        let prefix = 3
        var count = 0
        //3.每样最多prefix个,进行分类挑选
        for transaction in sortedTransactions {
            switch transaction.transactionState {
            case .purchasing:
                if purchasingArray.count < prefix{
                    purchasingArray.append(transaction)
                }
            case .purchased:
                if purchasedArray.count < prefix{
                    purchasedArray.append(transaction)
                }
            case .failed:
                if failedArray.count < prefix{
                    failedArray.append(transaction)
                }
            case .restored:
                if restoredArray.count < prefix{
                    restoredArray.append(transaction)
                }
            case .deferred:
                if deferredArray.count < prefix{
                    deferredArray.append(transaction)
                }
            @unknown default:
                break
            }
            
            count+=1
            if purchasingArray.count == prefix,
               purchasedArray.count == prefix,
               failedArray.count == prefix,
               restoredArray.count == prefix,
               deferredArray.count == prefix
            {
                break
            }
        }
        
        
        //4.结果汇总,时间排序
        let resultArray = purchasingArray + purchasedArray + failedArray + restoredArray + deferredArray
        let sortedResultArray = resultArray.sorted { transaction1, transaction2 in
            if let date1 = transaction1.transactionDate,let date2 = transaction2.transactionDate{
                return date1 > date2
            }
            return true
        }
        
        return sortedResultArray
    }
}

// MARK: 订阅回调
extension PurchaseManager: SKPaymentTransactionObserver {
    public func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
        
        //过滤下数据
        let transactions = filterTransactions(transactions: transactions)
        
        // 因为只有订阅类的购买项
        for transaction in transactions {
            
//            if transaction.transactionState != .purchasing {
//                SKPaymentQueue.default().finishTransaction(transaction)
//                continue
//            }
            switch transaction.transactionState {
            case .purchasing:   
                // Transaction is being added to the server queue.
                delegate?.purchase(self, didChaged: .paying, object: nil)
                
            case .purchased:    
                // Transaction is in queue, user has been charged.  Client should complete the transaction.
                verifyPayResult(transaction: transaction, useSandBox: false)
                
            case .failed:       
                // Transaction was cancelled or failed before being added to the server queue.
                SKPaymentQueue.default().finishTransaction(transaction)
                var message = "Payment Failed"
                if let error = transaction.error as? SKError,
                   error.code == SKError.paymentCancelled {
                    message = "The subscription was canceled"
                }
                delegate?.purchase(self, didChaged: .payFail, object: message)
                
            case .restored:     
                // Transaction was restored from user's purchase history.  Client should complete the transaction.
                if let original = transaction.original,
                    original.transactionState == .purchased {
                    verifyPayResult(transaction: transaction, useSandBox: false)
                }
                else {
                    delegate?.purchase(self, didChaged: .restoreFail, object: "Failed to restore subscribe, please try again")
                    SKPaymentQueue.default().finishTransaction(transaction)
                }
                
            case .deferred:     // The transaction is in the queue, but its final status is pending external action.
                break
            @unknown default:
                SKPaymentQueue.default().finishTransaction(transaction)
            }
        }
    }
    
    public func paymentQueue(_ queue: SKPaymentQueue, restoreCompletedTransactionsFailedWithError error: Error) {
        delegate?.purchase(self, didChaged: .restoreFail, object: nil)
    }
    
    public func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) {
        if let trans = queue.transactions.first(where: { $0.transactionState == .purchased }) {
            verifyPayResult(transaction: trans, useSandBox: false)
        } else if queue.transactions.isEmpty {
            delegate?.purchase(self, didChaged: .restoreFail, object: "You don't have an active subscription")
        }
    }
}

extension PurchaseManager {
    func verifyPayResult(transaction: SKPaymentTransaction, useSandBox: Bool) {
        delegate?.purchase(self, didChaged: .verifying, object: nil)
        
        guard let url = Bundle.main.appStoreReceiptURL,
              let receiptData = try? Data(contentsOf: url) else {
            delegate?.purchase(self, didChaged: .verifyFail, object: "凭证文件为空")
            return
        }
        
        let requestContents = [
            "receipt-data": receiptData.base64EncodedString(),
            "password": "61ea7bd16df442b283dbe542b8ca1a7a",
        ]
        guard let requestData = try? JSONSerialization.data(withJSONObject: requestContents) else {
            delegate?.purchase(self, didChaged: .verifyFail, object: "凭证文件为空")
            return
        }
        
        let verifyUrlString = useSandBox ? Config.sandBoxUrl : Config.verifyUrl
        let verifyUrl = URL(string: verifyUrlString)!
        if var request = try? URLRequest(url: verifyUrl, method: .post) {
            request.timeoutInterval = 300
            request.httpBody = requestData
            
            AF.request(request)
                .responseData(completionHandler: { [weak self] (resp) in
                    guard let self = self else { return }
                    
                    if let data = resp.data,
                       let jsonResponse = try? JSONSerialization.jsonObject(with: data) as? [String: Any] {
                        
                        let status = jsonResponse["status"]
                        if let status = status as? String, status == "21007" {
                            self.verifyPayResult(transaction: transaction, useSandBox: true)
                        }
                        else if let status = status as? Int, status == 21007 {
                            self.verifyPayResult(transaction: transaction, useSandBox: true)
                        }
                        else if let status = status as? String, status == "0" {
                            self.handlerPayResult(transaction: transaction, resp: jsonResponse)
                        }
                        else if let status = status as? Int, status == 0 {
                            self.handlerPayResult(transaction: transaction, resp: jsonResponse)
                        }
                        else {
                            self.delegate?.purchase(self, didChaged: .verifyFail, object: "验证结果状态码错误:\(status.debugDescription)")
                        }
                    }
                    else {
                        self.delegate?.purchase(self, didChaged: .verifyFail, object: "验证结果为空")
                    }
                })
        }
    }
    
    func handlerPayResult(transaction: SKPaymentTransaction, resp: [String: Any]) {
        
        var isLifetime = false
        // 终生会员
        if let receipt = resp["receipt"] as? [String: Any],
           let in_app = receipt["in_app"] as? [[String: Any]] {
            if let lifetimeProductId = purchaseProducts.first(where: { $0.period == .lifetime })?.productId,
                let _ = in_app.filter({ ($0["product_id"] as? String) == lifetimeProductId }).first(where: { item in
                if let purchase_date = item["purchase_date"] as? String,
                   !purchase_date.isEmpty {
                    return true
                }
                else if let purchase_date_ms = item["purchase_date_ms"] as? String,
                        !purchase_date_ms.isEmpty {
                    return true
                }
                return false
            }) {
                updateExpireTime(self.lifetimeExpireTime, for: lifetimeProductId)
                isLifetime = true
            }
        }
        
        if !isLifetime {
            let info = resp["latest_receipt_info"] as? [[String: Any]]
            if let firstItem = info?.first,
                let expires_date_ms = firstItem["expires_date_ms"] as? String,
                let productId = firstItem["product_id"] as? String {
                self.updateExpireTime(expires_date_ms, for: productId)
            }
        }
        
        SKPaymentQueue.default().finishTransaction(transaction)
        
        DispatchQueue.main.async {
            if transaction.transactionState == .restored {
                self.delegate?.purchase(self, didChaged: .restoreSuccess, object: nil)
            }
            else {
                self.delegate?.purchase(self, didChaged: .paySuccess, object: nil)
            }
        }
    }
    
    // 终生会员过期时间：100年
    var lifetimeExpireTime: String {
        let date = Date().addingTimeInterval(100 * 365 * 24 * 60 * 60)
        return "\(date.timeIntervalSince1970*1000)"
    }
}

public extension PurchaseManager {
    func canContinue(_ requireVip: Bool) -> Bool {
        guard requireVip else {
            return true
        }
        return isVip
    }
}
